


#include  "ESS_CommonDefine.h"
#include  "PackInfor\PackInformationReading.h"
#include "Drivers\Drivers.h"

#define Avg_array_size  10


typedef struct {
  int Values[Avg_array_size];
  unsigned int index; 
  unsigned char filledOnceFlag;
} CurrentStruct;

CurrentStruct ModuleCurrent;


////////////////////////////////////////
extern unsigned int G_Module_Voltage;
extern int G_Module_Current;
extern int G_Avg_Module_Current;
extern unsigned int G_Module_Status;

unsigned char G_Indication_Comm_Failure_M1;
unsigned char G_Indication_Comm_Failure_M2;
unsigned char G_Indication_Comm_Failure_M3;
//extern unsigned char G_Indication_Comm_Failure_M1;
//extern unsigned char G_Indication_Comm_Failure_M2;
//extern unsigned char G_Indication_Comm_Failure_M3;
unsigned char G_Indication_SOH_Failure_M1;
unsigned char G_Indication_SOH_Failure_M2;
unsigned char G_Indication_SOH_Failure_M3;
//extern unsigned char G_Indication_FCC_Failure_M1;
//extern unsigned char G_Indication_FCC_Failure_M2;
//extern unsigned char G_Indication_FCC_Failure_M3;
/////////////////////////////////////////////
// only for SOH1 and SOH2 Indication 
unsigned char G_Indication_FCC_Failure_M1;
unsigned char G_Indication_FCC_Failure_M2;
unsigned char G_Indication_FCC_Failure_M3;
unsigned char G_Indication_CycleCount_Failure_M1;
unsigned char G_Indication_CycleCount_Failure_M2;
unsigned char G_Indication_CycleCount_Failure_M3;
//////////////////////////////////////////////////////
// only for Pack FET Control status Indication
// turn on = 1, turn off = 0.
unsigned char G_Indication_DSGFET_M1;
unsigned char G_Indication_DSGFET_M2;
unsigned char G_Indication_DSGFET_M3;

unsigned char G_Indication_CHGFET_M1;
unsigned char G_Indication_CHGFET_M2;
unsigned char G_Indication_CHGFET_M3;
//////////////////////////////////////////////////////

/*
extern unsigned char Module_OT;
extern unsigned char Module_UV;
extern unsigned char Module_OV;
extern unsigned char Module_D_OC;
extern unsigned char Module_C_OC;
extern unsigned char Module_DSG;
extern unsigned char Module_TCA;
*/

extern ModuleSet module[NumOfSerialModules];
unsigned char RedLEDBlinkingFalg;
void UpdatedModuleStatusForSeriesBlockOccursFailure();


void InitSystemInfo(){
  unsigned int loop_i;
  ModuleCurrent.index = 0;
  ModuleCurrent.filledOnceFlag = false;
  for(loop_i = 0; loop_i < Avg_array_size; loop_i++){
    ModuleCurrent.Values[loop_i] = 0;
  }
  G_Module_Status = 0;
  
  RedLEDBlinkingFalg = false;
  
}

void setCurrentToArray( int current){
  ModuleCurrent.Values[ModuleCurrent.index] = current;
  ModuleCurrent.index++;
  if(ModuleCurrent.index >= Avg_array_size){
    ModuleCurrent.index = 0;
    ModuleCurrent.filledOnceFlag = true;
  }
}
unsigned int getSystemVoltage(){
  return calculateSystemVoltage();
}
int getSystemCurrent(){
  return G_Module_Current;  
}
int getAvgSystemCurrent(){
  long int total;
  unsigned int loop_i;
  total = 0;
  if(ModuleCurrent.filledOnceFlag){
    for(loop_i = 0; loop_i < Avg_array_size; loop_i++){
      total += ModuleCurrent.Values[loop_i];
    }
    return (int)(total/Avg_array_size);
  }else{
    for(loop_i = 0; loop_i < ModuleCurrent.index; loop_i++){
      total += ModuleCurrent.Values[loop_i];
    }
    return (int)(total/ModuleCurrent.index);
  }
}

char isSystemNoPackFail(){
  
  unsigned char state;
    //communication fail
    state = G_Indication_Comm_Failure_M1;
    state |= G_Indication_Comm_Failure_M2;
    state |= G_Indication_Comm_Failure_M3;
    //Pack MosFet has been turn off
    state |= ~G_Indication_DSGFET_M1;
    state |= ~G_Indication_DSGFET_M2;
    state |= ~G_Indication_DSGFET_M3;
    state |= ~G_Indication_CHGFET_M1;
    state |= ~G_Indication_CHGFET_M2;
    state |= ~G_Indication_CHGFET_M3;
    if(state){
      return false;
    }else{
      return true;
    }
}
//////////////////////////////////////////////////////////////////////////////
// G_Indication_Comm_Failure_Mx : 
// using bit0~bit5 represent Pack _A~_F fail
void setPackCommunicationFailure(char moduleName, char packName, char failureFlag){
  char databit;
  databit = 1;
  databit = databit << packName;
  
  switch(moduleName){
    case _M1:
      if(failureFlag){
        G_Indication_Comm_Failure_M1 |=  databit;
      }else{
        G_Indication_Comm_Failure_M1 &=  ~databit;
      }
      break;
    case _M2:
      if(failureFlag){
        G_Indication_Comm_Failure_M2 |=  databit;
      }else{
        G_Indication_Comm_Failure_M2 &=  ~databit;
      }
      break;
    case _M3:
      if(failureFlag){
        G_Indication_Comm_Failure_M3 |=  databit;
      }else{
        G_Indication_Comm_Failure_M3 &=  ~databit;
      }
      break;
  }
  
  UpdatedModuleStatusForSeriesBlockOccursFailure();
}
//////////////////////////////////////////////////////////////////////////////
// G_Indication_SOH_Failure_Mx : 
// using bit0~bit5 represent Pack _A~_F fail
void setPackSOHFailure(char moduleName, char packName, char failureFlag){
  char databit;
  databit = 1;
  databit = databit << packName;
  
    switch(moduleName){
      case _M1:
        if(failureFlag){
          G_Indication_SOH_Failure_M1 |=  databit;
        }else{
          G_Indication_SOH_Failure_M1 &=  ~databit;
        }
        break;
      case _M2:
        if(failureFlag){
          G_Indication_SOH_Failure_M2 |=  databit;
        }else{
          G_Indication_SOH_Failure_M2 &=  ~databit;
        }
        break;
      case _M3:
        if(failureFlag){
          G_Indication_SOH_Failure_M3 |=  databit;
        }else{
          G_Indication_SOH_Failure_M3 &=  ~databit;
        }
        break;
    }
    if(G_Indication_SOH_Failure_M1 > 0 || G_Indication_SOH_Failure_M2 > 0 || G_Indication_SOH_Failure_M3 > 0){
      setYellowLED(DeviceOn);
    }else{
      setYellowLED(DeviceOff);
    }
}
//////////////////////////////////////////////////////////////////////////////
// G_Indication_FCC_Failure_Mx : 
// using bit0~bit5 represent Pack _A~_F fail
void setPackFCCFailure(char moduleName, char packName, char failureFlag){
  char databit;
  databit = 1;
  databit = databit << packName;
  
    switch(moduleName){
      case _M1:
        if(failureFlag){
          G_Indication_FCC_Failure_M1 |=  databit;
        }else{
          G_Indication_FCC_Failure_M1 &=  ~databit;
        }
        break;
      case _M2:
        if(failureFlag){
          G_Indication_FCC_Failure_M2 |=  databit;
        }else{
          G_Indication_FCC_Failure_M2 &=  ~databit;
        }
        break;
      case _M3:
        if(failureFlag){
          G_Indication_FCC_Failure_M3 |=  databit;
        }else{
          G_Indication_FCC_Failure_M3 &=  ~databit;
        }
        break;
    }
    if(G_Indication_FCC_Failure_M1 > 0 || G_Indication_FCC_Failure_M2 > 0 || G_Indication_FCC_Failure_M3 > 0){
      G_Module_Status |= SOH1;
    }else{
      G_Module_Status &= ~SOH1;
    }
}
//////////////////////////////////////////////////////////////////////////////
// G_Indication_CycleCountFailure_Mx : 
// using bit0~bit5 represent Pack _A~_F fail
void setPackCycleCountFailure(char moduleName, char packName, char failureFlag){
  char databit;
  databit = 1;
  databit = databit << packName;
  
    switch(moduleName){
      case _M1:
        if(failureFlag){
          G_Indication_CycleCount_Failure_M1 |=  databit;
        }else{
          G_Indication_CycleCount_Failure_M1 &=  ~databit;
        }
        break;
      case _M2:
        if(failureFlag){
          G_Indication_CycleCount_Failure_M2 |=  databit;
        }else{
          G_Indication_CycleCount_Failure_M2 &=  ~databit;
        }
        break;
      case _M3:
        if(failureFlag){
          G_Indication_CycleCount_Failure_M3 |=  databit;
        }else{
          G_Indication_CycleCount_Failure_M3 &=  ~databit;
        }
        break;
    }
    if(G_Indication_CycleCount_Failure_M1 > 0 || G_Indication_CycleCount_Failure_M2 > 0 || G_Indication_CycleCount_Failure_M3 > 0){
      G_Module_Status |= SOH2;
    }else{
      G_Module_Status &= ~SOH2;
    }
}
//////////////////////////////////////////////////////////////////////////////
// SET  PackFETStatus by Pack FET control register
// bit1 = DSG MosFET, bit2 = CHG MosFET
void setPackFETStatus(char moduleName, char packName, unsigned char FETControl){
  char databit, dsg, chg;
  databit = 1;
  databit = databit << packName;
  
  dsg = FETControl & PackFETDSGBit;
  chg = FETControl & PackFETCHGBit;
  
    switch(moduleName){
      case _M1:
        if(dsg){
          G_Indication_DSGFET_M1 |=  databit;
        }else{
          G_Indication_DSGFET_M1 &=  ~databit;
        }
        if(chg){
          G_Indication_CHGFET_M1 |=  databit;
        }else{
          G_Indication_CHGFET_M1 &=  ~databit;
        }
        break;
      case _M2:
        if(dsg){
          G_Indication_DSGFET_M2 |=  databit;
        }else{
          G_Indication_DSGFET_M2 &=  ~databit;
        }
        if(chg){
          G_Indication_CHGFET_M2 |=  databit;
        }else{
          G_Indication_CHGFET_M2 &=  ~databit;
        }
        break;
      case _M3:
        if(dsg){
          G_Indication_DSGFET_M3 |=  databit;
        }else{
          G_Indication_DSGFET_M3 &=  ~databit;
        }
        if(chg){
          G_Indication_CHGFET_M3 |=  databit;
        }else{
          G_Indication_CHGFET_M3 &=  ~databit;
        }
        break;
    }
    UpdatedModuleStatusForSeriesBlockOccursFailure();
    
}

void UpdatedModuleStatusForSeriesBlockOccursFailure(){
  
  unsigned char dsg,chg;
  
  dsg = (~G_Indication_DSGFET_M1) & 0x3f;
  chg = (~G_Indication_CHGFET_M1) & 0x3f;
  
  if(dsg || chg || G_Indication_Comm_Failure_M1){
    G_Module_Status |= S1;
  }else{
    G_Module_Status &= ~S1;
  }
  
  dsg = (~G_Indication_DSGFET_M2) & 0x3f;
  chg = (~G_Indication_CHGFET_M2) & 0x3f;
  
  if(dsg || chg || G_Indication_Comm_Failure_M2){
    G_Module_Status |= S2;
  }else{
    G_Module_Status &= ~S2;
  }
  
  dsg = (~G_Indication_DSGFET_M3) & 0x3f;
  chg = (~G_Indication_CHGFET_M3) & 0x3f;
  
  if(dsg || chg || G_Indication_Comm_Failure_M3){
    G_Module_Status |= S3;
  }else{
    G_Module_Status &= ~S3;
  } 
}



void CheckSystemOnePackFailureForLEDBlinking(){
  
	////////////////////////////////////
	// set LED Blink
  if(G_Indication_DSGFET_M1 != 0x3f ||
     G_Indication_DSGFET_M2 != 0x3f ||
     G_Indication_DSGFET_M3 != 0x3f ||
     G_Indication_CHGFET_M1 != 0x3f ||
     G_Indication_CHGFET_M2 != 0x3f ||
     G_Indication_CHGFET_M3 != 0x3f ||
     G_Indication_Comm_Failure_M1 != 0x00 ||
     G_Indication_Comm_Failure_M2 != 0x00 ||
     G_Indication_Comm_Failure_M3 != 0x00 ||
     (G_Module_Status & OTA) != 0)
  {
    if(!RedLEDBlinkingFalg){
      setTimerFuncForBlink(&setRedLED, true, 5); //delay50ms_count = 20 ==> ~1000ms
      RedLEDBlinkingFalg = true;
    }
  }else{
    disableTimerFuncForBlink();
    setRedLED(DeviceOff);
    RedLEDBlinkingFalg = false;
  }
  
}

///////////////////////////////////////////////////////////////////
// For ESS System Failure checking,
// default if two or more packs fail
char CheckSystemFailure(){
  char fail_count1,fail_count2,fail_count3;
  char loop_i;
  //unsigned char cbits;

  fail_count1 = 0;
  fail_count2 = 0;
  fail_count3 = 0;
  /////////////////////////////////////////////
  // Check Communication fail.
  // if there are two or more packs fail in any one parallel module,
  // into failshutdown mode
  for(loop_i = _A; loop_i <= _F; loop_i++){
    if(module[_M1].pack[loop_i].packFail != PackNormal && 
       module[_M1].pack[loop_i].packCommunctionFailTimes > _PackCommunctionMaxFailTimes_){
      fail_count1++;
    }
    if(module[_M2].pack[loop_i].packFail != PackNormal &&
       module[_M2].pack[loop_i].packCommunctionFailTimes > _PackCommunctionMaxFailTimes_){
      fail_count2++;
    }
    if(module[_M3].pack[loop_i].packFail != PackNormal &&
       module[_M3].pack[loop_i].packCommunctionFailTimes > _PackCommunctionMaxFailTimes_){
      fail_count3++;
    }
  }
  if( fail_count1 > PermittingPackFailureNumOfModule || 
      fail_count2 > PermittingPackFailureNumOfModule || 
      fail_count3 > PermittingPackFailureNumOfModule ){
  	return NBPCFail;
  }

  /////////////////////////////////////////////
  // Check Pack Mos FET turn off.
  // if there are two or more packs fail in any one parallel module,
  // into failshutdown mode
  for(loop_i = _A; loop_i <= _F; loop_i++){
    if(module[_M1].pack[loop_i].packFail == PackNormal &&
       module[_M1].pack[loop_i].packInfoFail[ManufacturerAccess] == PackNormal)
    {
        if(!isPackFETTurnOn_ByManufacturerAccess(_M1, loop_i))
        {
          fail_count1++;
        }
    }//m1
    if(module[_M2].pack[loop_i].packFail == PackNormal &&
       module[_M2].pack[loop_i].packInfoFail[ManufacturerAccess] == PackNormal)
    {
        if(!isPackFETTurnOn_ByManufacturerAccess(_M2, loop_i))
        {
          fail_count2++;
        }
    }//m2
    if(module[_M3].pack[loop_i].packFail == PackNormal &&
       module[_M3].pack[loop_i].packInfoFail[ManufacturerAccess] == PackNormal)
    {
        if(!isPackFETTurnOn_ByManufacturerAccess(_M3, loop_i))
        {
          fail_count3++;
        }
    }//m1
  }//for(loop_i = _A; loop_i <= _F; loop_i++){
  if( fail_count1 > PermittingPackFailureNumOfModule || 
      fail_count2 > PermittingPackFailureNumOfModule || 
      fail_count3 > PermittingPackFailureNumOfModule ){
  	return NBPCFail;
  } 
  
/*  
  fail_count1 = 0;
  fail_count2 = 0;
  fail_count3 = 0;
  /////////////////////////////////////////////
  // Check SOH fail.
  // if there are two or more packs fail in any one parallel module,
  // into failshutdown mode
  if(G_Indication_SOH_Failure_M1 > 0){
    for(loop_i = 0; loop_i < 8; loop_i++){
      cbits = 0x01;
      cbits <<= loop_i;
      if(G_Indication_SOH_Failure_M1 & cbits){
        fail_count1++;
      }
    }
  }
  if(G_Indication_SOH_Failure_M2 > 0){
    for(loop_i = 0; loop_i < 8; loop_i++){
      cbits = 0x01;
      cbits <<= loop_i;
      if(G_Indication_SOH_Failure_M2 & cbits){
        fail_count2++;
      }
    }
  }
  if(G_Indication_SOH_Failure_M3 > 0){
    for(loop_i = 0; loop_i < 8; loop_i++){
      cbits = 0x01;
      cbits <<= loop_i;
      if(G_Indication_SOH_Failure_M3 & cbits){
        fail_count3++;
      }
    }
  }
  if( fail_count1 > PermittingPackFailureNumOfModule || 
      fail_count2 > PermittingPackFailureNumOfModule || 
      fail_count3 > PermittingPackFailureNumOfModule ){
  	return NBPCFail;
  }
*/  

  return NoneFail;
}//CheckSystemFailure()

//void moduleStatusUpdated(){
//
//
//  if(Module_D_OC){
//    G_Module_Status |= D_OC;
//  }else{
//    G_Module_Status &= ~D_OC;
//  }
//
//  if(Module_C_OC){
//    G_Module_Status |= C_OC;
//  }else{
//    G_Module_Status &= ~C_OC;
//  }
//
//  if(Module_DSG){
//    G_Module_Status |= DSG;
//  }else{
//    G_Module_Status &= ~DSG;
//  }
//  
//  if(Module_UV){
//    G_Module_Status |= TDA;
//  }else{
//    G_Module_Status &= ~TDA;
//  }
//  
//  if(Module_OT){
//    G_Module_Status |= OTA;
//  }else{
//    G_Module_Status &= ~OTA;
//  }
//   
//  if(Module_TCA){
//    G_Module_Status |= TCA;
//  }else{
//    G_Module_Status &= ~TCA;
//  }
//
//  if(Module_OV){
//    G_Module_Status |= OCA;
//  }else{
//    G_Module_Status &= ~OCA;
//  }
//  if(G_Indication_Comm_Failure_M1 || G_Indication_FCC_Failure_M1){
//    G_Module_Status |= S1;
//  }else{
//    G_Module_Status &= ~S1;
//  }
//  if(G_Indication_Comm_Failure_M2 || G_Indication_FCC_Failure_M2){
//    G_Module_Status |= S2;
//  }else{
//    G_Module_Status &= ~S2;
//  }
//  if(G_Indication_Comm_Failure_M3 || G_Indication_FCC_Failure_M3){
//    G_Module_Status |= S3;
//  }else{
//    G_Module_Status &= ~S3;
//  }
//}



//////////////////////////////////////////////////
// Utility Functions
int calculateSystemCurrent(){
    long systemCurrent = 0;
    int value_1 = 0;
    int value_2 = 0;
		value_1 = getModuleCurrent(_M1);
		if(value_1 != 0x07ff){
			systemCurrent += value_1;
			value_2++;
		}
		value_1 = getModuleCurrent(_M2);
		if(value_1 != 0x07ff){
			systemCurrent += value_1;
			value_2++;
		}
		value_1 = getModuleCurrent(_M3);
		if(value_1 != 0x07ff){
			systemCurrent += value_1;
			value_2++;
		}
		return systemCurrent / value_2;
}
int getModuleCurrent(char module_Num){

  int pack_, values;
  long total;
  char count = 0;
  values = 0;
  total = 0;
  
  for(pack_ = 0; pack_< NumOfParallelPacks; pack_++){
	  if(module[module_Num].pack[pack_].packInfoFail[current] == PackNormal){
      values = module[module_Num].pack[pack_].packInfo[current][1] << 8;
      values |= module[module_Num].pack[pack_].packInfo[current][0];
      total += values;
	  	count++;
	  }
	}
  return (int)total;
  
/*  
	if(count > 0){
    return (int)(total / count);
	}else{
		return 0x7fff;
	}
*/

}

unsigned int calculateSystemVoltage(){
    unsigned long systemVoltage = 0;
    int value_1 = 0;
    int value_2 = 0;
		value_1 = getModuleVoltage(_M1);
		if(value_1 != 0x07ff){
			systemVoltage += value_1;
			value_2++;
		}
		value_1 = getModuleVoltage(_M2);
		if(value_1 != 0x07ff){
			systemVoltage += value_1;
			value_2++;
		}
		value_1 = getModuleVoltage(_M3);
		if(value_1 != 0x07ff){
			systemVoltage += value_1;
			value_2++;
		}
		return systemVoltage;
}
int getModuleVoltage(char module_Num){

  int pack_, values;
  long total;
  char count = 0;
  values = 0;
  total = 0;
  
  for(pack_ = 0; pack_< NumOfParallelPacks; pack_++){
	  if(module[module_Num].pack[pack_].packInfoFail[voltage] == PackNormal){
      values = module[module_Num].pack[pack_].packInfo[voltage][1] << 8;
      values |= module[module_Num].pack[pack_].packInfo[voltage][0];
      total += values;
	  	count++;
	  }
	}
	if(count > 0){
		return (int)(total / count);
	}else{
		return 0x7fff;
	}
}